﻿using HandyControl.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Window = System.Windows.Window;

namespace PositionDataSets
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        int font_size_min = 12;
        int font_size_max = 64;
        int set_label_len = 400;
        Random random = new Random();

        public MainWindow()
        {
            InitializeComponent();
        }

        int GetLabelCount(int font_size) 
        {
            return set_label_len / font_size;
        }

        private void btnCreate_Click(object sender, RoutedEventArgs e)
        {
            if (!Directory.Exists("Fonts"))
            {
                System.Windows.MessageBox.Show("请选择字体！");
                return;
            }
            if (!Directory.Exists("BackImgs"))
            {
                System.Windows.MessageBox.Show("请选择背景图！");
                return;
            }
            if (!Directory.Exists("DataSets"))
            {
                Directory.CreateDirectory("DataSets");
            }
            int start_count = int.Parse(tbStart.Text);
            int total_times = int.Parse(tbCount.Text);
            List<ImageBrush> listImages = new List<ImageBrush>();
            string[] files = Directory.GetFiles("BackImgs");
            foreach (string file in files)
            {
                listImages.Add(new ImageBrush(new BitmapImage(new Uri(file, UriKind.RelativeOrAbsolute))));
            }
            List<FontFamily> listfonts = new List<FontFamily>();
            files = Directory.GetFiles("Fonts");
            foreach (string file in files) 
            {
                string fontname = file.Substring(file.LastIndexOf('\\') + 1);
                fontname = fontname.Substring(0, fontname.IndexOf('.'));
                listfonts.Add(new FontFamily(fontname));
            }
            cvLabel.Children.Clear();
            for (int i = 0; i < total_times; i++)
            {
                byte BR = (byte)random.Next(0, 256);
                byte BG = (byte)random.Next(0, 256);
                byte BB = (byte)random.Next(0, 256);
                SolidColorBrush back = new SolidColorBrush(Color.FromRgb(BR, BG, BB));
                cvMain.Background = back;
                double total_height = 0;
                StringBuilder sblabel = new StringBuilder();
                cvText.Children.Clear();
                double lasttop = 0, lastleft = 0, lastangle = 0, lastwidth = 512, lastheight = 0;
                while (total_height < 512)
                {
                    //字体、尺寸、内容
                    OutlineText tbText = new OutlineText();
                    RotateTransform tbAngle = new RotateTransform();
                    tbText.RenderTransform = tbAngle;
                    int font_size = random.Next(font_size_min, font_size_max);
                    tbText.Text = GetRandomLabel(font_size);
                    tbText.FontFamily = listfonts[random.Next(listfonts.Count)];
                    tbText.FontSize = font_size;
                    tbText.StrokeThickness = 1;
                    tbText.StrokePosition = HandyControl.Data.StrokePosition.Outside;
                    cvText.Children.Add(tbText);
                    DoEvents();
                    //角度
                    double angle = (random.NextDouble() - 0.5) * 40; // -20 ~ 20 要求识别角度不能太大
                    tbAngle.Angle = angle;
                    //位置
                    double width = tbText.ActualWidth;
                    double height = tbText.ActualHeight;
                    //计算外框位置
                    double borderWidth = width * Math.Cos(angle / 180 * Math.PI) + Math.Abs(height * Math.Sin(angle / 180 * Math.PI));
                    double borderHeight = height * Math.Cos(angle / 180 * Math.PI) + Math.Abs(width * Math.Sin(angle / 180 * Math.PI));
                    //计算坐标位置
                    double topOff = 0;
                    double bd_left = random.NextDouble() * (cvMain.Width - borderWidth);
                    double left = bd_left;
                    if (angle > 0)
                    {
                        left += height * Math.Sin(angle / 180 * Math.PI);
                    }
                    else
                    {
                        topOff -= width * Math.Sin(angle / 180 * Math.PI);
                    }
                    double top = JudgOverlap(lasttop, lastleft, lasttop + topOff, left, lastangle, angle, lastwidth, width, lastheight, height);
                    double bd_top = top - topOff;
                    total_height = bd_top + borderHeight;
                    if (total_height > 512)
                    {
                        cvText.Children.RemoveAt(cvText.Children.Count - 1);
                        break;
                    }
                    sblabel.Append(String.Format("text:{0}\n", tbText.Text));
                    sblabel.Append(String.Format("left:{0}\ntop:{1}\n", bd_left, bd_top));
                    sblabel.Append(String.Format("height:{0}\nwidth:{1}\ntxtheight:{2}\nangle:{3}\n", borderHeight, borderWidth, height, angle));
                    Canvas.SetLeft(tbText, left);
                    Canvas.SetTop(tbText, top);

                    lasttop = top;
                    lastleft = left;
                    lastangle = angle;
                    lastwidth = width;
                    lastheight = height;

                    //颜色（字体颜色、描边颜色、背景色）
                    byte R = (byte)random.Next(0, 256);
                    byte G = (byte)random.Next(0, 256);
                    byte B = (byte)random.Next(0, 256);
                    SolidColorBrush fill = new SolidColorBrush(Color.FromRgb(R, G, B));
                    while ((Math.Abs(R - BR) < 30 && Math.Abs(G - BG) < 30 && Math.Abs(B - BB) < 30))
                    {
                        R = (byte)random.Next(0, 256);
                        G = (byte)random.Next(0, 256);
                        B = (byte)random.Next(0, 256);
                    }
                    tbText.Fill = fill;
                    tbText.Stroke = back;
                }
                tbInfo.Text = sblabel.ToString();
                bdBack.Visibility = Visibility.Collapsed;
                bdNoise.Visibility = Visibility.Collapsed;
                //加背景
                if (random.Next(100) > 80) 
                {
                    bdBack.Background = listImages[random.Next(listImages.Count)];
                    bdBack.Width = random.Next((int)cvMain.Width, (int)cvMain.Width * 2);
                    bdBack.Height = random.Next((int)cvMain.Width, (int)cvMain.Width * 2);
                    Canvas.SetLeft(bdBack, random.NextDouble() * (cvMain.Width - bdBack.Width));
                    Canvas.SetTop(bdBack, random.NextDouble() * (cvMain.Height - bdBack.Height));
                    bdBack.Visibility = Visibility.Visible;
                    bdBack.Opacity = random.NextDouble() * 0.3 + 0.7;
                }
                //加噪音
                if (random.Next(100) > 80)
                {
                    bdNoise.Background = listImages[random.Next(listImages.Count)];
                    bdNoise.Width = random.Next((int)cvMain.Width, (int)cvMain.Width * 2);
                    bdNoise.Height = random.Next((int)cvMain.Width, (int)cvMain.Width * 2);
                    Canvas.SetLeft(bdNoise, random.NextDouble() * (cvMain.Width - bdBack.Width));
                    Canvas.SetTop(bdNoise, random.NextDouble() * (cvMain.Height - bdBack.Height));
                    bdNoise.Visibility = Visibility.Visible;
                    bdNoise.Opacity = random.NextDouble() * 0.3 + 0.1;
                }
                DoEvents();
                if ((bool)cbCreate.IsChecked)
                {
                    FileStream fs = new FileStream("DataSets/" + (start_count + i).ToString() + ".jpg", FileMode.Create);//保存在特定路径
                    RenderTargetBitmap bmp = new RenderTargetBitmap((int)cvMain.ActualWidth, (int)cvMain.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                    bmp.Render(cvMain);
                    BitmapEncoder encoder = new JpegBitmapEncoder();//对象的集合编码转成图像流
                    encoder.Frames.Add(BitmapFrame.Create(bmp));
                    encoder.Save(fs);//保存到路径中
                    fs.Close();//释放资源
                    fs.Dispose();
                    File.WriteAllText("DataSets/" + (start_count + i).ToString() + ".txt", sblabel.ToString());
                }
                if ((bool)cbShow.IsChecked) 
                {
                    ShowLabel(sblabel.ToString());
                }
                tbStart.Text = (start_count + i).ToString();
                tbCount.Text = (total_times - i).ToString();
            }
            tbCount.Text = "1";
        }

        private void ShowLabel(string label_str)
        {
            cvLabel.Children.Clear();
            string[] items = label_str.Split('\n');
            for (int i = 0; i < items.Length / 7; i++) 
            { 
                double left = double.Parse(items[1 + i * 7].Substring(items[1 + i * 7].IndexOf(":") + 1));
                double top = double.Parse(items[2 + i * 7].Substring(items[2 + i * 7].IndexOf(":") + 1));
                double height = double.Parse(items[3 + i * 7].Substring(items[3 + i * 7].IndexOf(":") + 1));
                double width = double.Parse(items[4 + i * 7].Substring(items[4 + i * 7].IndexOf(":") + 1));
                double txtheight = double.Parse(items[5 + i * 7].Substring(items[5 + i * 7].IndexOf(":") + 1));
                double angle = double.Parse(items[6 + i * 7].Substring(items[6 + i * 7].IndexOf(":") + 1));
                AddLabelShow(left, top, height, width, txtheight, angle);
            }
        }

        private void AddLabelShow(double left, double top, double height, double width, double txtheight, double angle)
        {
            Border bd = new Border();
            bd.Width = width;
            bd.Height = height;
            bd.Background = Brushes.Yellow;
            bd.Opacity = 0.3;
            Canvas.SetLeft(bd, left);
            Canvas.SetTop(bd, top);
            double centerx = width / 2 + left;
            double centery = height / 2 + top;
            double k = Math.Atan(angle / 180 * Math.PI);
            double b = centery - k * centerx;
            double startx = left;
            double starty = k * startx + b;
            double endx = left + width;
            double endy = k * endx + b;
            Line line = new Line();
            line.X1 = startx;
            line.Y1 = starty;
            line.X2 = endx;
            line.Y2 = endy;
            line.Stroke = Brushes.Green;
            line.StrokeThickness = 1;
            cvLabel.Children.Add(bd);
            cvLabel.Children.Add(line);
        }


        private double JudgOverlap(double top1, double left1, double top2, double left2, double angle1, double angle2, double width1, double width2, double height1, double height2)
        {
            double k1 = Math.Tan(angle1 / 180 * Math.PI);
            double b1 = top1 - k1 * left1;
            double k2 = Math.Tan(angle2 / 180 * Math.PI);
            double b2 = top2 - k2 * left2;
            double end2x = left2 + width2 * Math.Cos(angle2 / 180 * Math.PI);
            double end2y = top2 + width2 * Math.Sin(angle2 / 180 * Math.PI);
            double end1x = left1 + width1 * Math.Cos(angle1 / 180 * Math.PI);
            double end1y = top1 + width1 * Math.Sin(angle1 / 180 * Math.PI);

            double dis1 = (left2 * k1 + b1 - top2) + height1;
            if (left1 > left2) 
            {
                dis1 = (top1 - left1 * k2 - b2) + height1;
            }
            double dis2 = (end2x * k1 + b1 - end2y) + height1;
            if (end1x < end2x) 
            {
                dis2 = (end1y - end1x * k2 - b2) + height1;
            }
            if (dis1 > dis2 && dis1 > 0)
            {//有交叉
                return top2 + dis1;
            }
            if (dis1 < dis2 && dis2 > 0)
            {//有交叉
                return top2 + dis2;
            }

            return top2;
        }

        private void ExportAllTxt()
        {
            if (!File.Exists("DataSets/AllWords.TXT")) 
            {
                StringBuilder sball = new StringBuilder();
                for (int i = 0; i < 10; i++) { sball.Append(i.ToString()); };
                for (int i = 0; i < 26; i++) { sball.Append(((char)('a' + random.Next(26))).ToString()); };
                for (int i = 0; i < 26; i++) { sball.Append(((char)('A' + random.Next(26))).ToString()); };

                int totolcount = 40 * 93 - 5;
                Encoding gb = Encoding.GetEncoding("gb2312");
                for (int j = 0; j < totolcount; j++)
                {
                    int regionCode = 16 + j / 93;
                    int positionCode = 1 + j % 93;
                    int regionCode_Machine = regionCode + 160;// 160即为十六进制的20H+80H=A0H   
                    int positionCode_Machine = positionCode + 160;// 160即为十六进制的20H+80H=A0H   

                    // 转换为汉字   
                    byte[] bytes = new byte[] { (byte)regionCode_Machine, (byte)positionCode_Machine };
                    sball.Append(gb.GetString(bytes));
                }
                sball.Append(AllPunctuation);
                File.WriteAllText("DataSets/AllWords.TXT", sball.ToString());
            }
        }

        string AllPunctuation = "，。、：；‘’（）！？“”《》<>=*%.{}[]【】/\\";

        private string GetRandomLabel(int font_size)
        {
            int label_len = GetLabelCount(font_size);
            string label = "";
            switch (random.Next(20))
            {
                case 0: //数字
                    for (int i = 0; i < label_len; i++) { label += random.Next(10).ToString(); };
                    break;
                case 1://字母小写
                    for (int i = 0; i < label_len; i++) { label += ((char)('a' + random.Next(26))).ToString(); };
                    break;
                case 2://字母大写
                    for (int i = 0; i < label_len; i++) { label += ((char)('A' + random.Next(26))).ToString(); };
                    break;
                default://汉字
                    label = GenerateChineseWords(label_len);
                    break;
            }
            return label;
        }

        
        private void Window_ContentRendered(object sender, EventArgs e)
        {
            //string test_label = "0123ABCDabcd你我他，。：-,.:";
            //tbText.FontSize = 24;
            //tbText.Width = 512;
            //tbText.Background = Brushes.White;
            //if (!Directory.Exists("fonts"))
            //{
            //    Directory.CreateDirectory("fonts");
            //}
            //foreach (FontFamily font in Fonts.SystemFontFamilies) 
            //{
            //    tbText.Text = test_label;
            //    tbText.FontFamily = font;
            //    DoEvents();
            //    FileStream fs = new FileStream(@"fonts/" + font.Source + ".jpg", FileMode.Create);//保存在特定路径
            //    RenderTargetBitmap bmp = new RenderTargetBitmap((int)this.tbText.ActualWidth, (int)this.tbText.ActualHeight, 96, 96, PixelFormats.Pbgra32);
            //    bmp.Render(this.tbText);
            //    BitmapEncoder encoder = new JpegBitmapEncoder();//对象的集合编码转成图像流
            //    encoder.Frames.Add(BitmapFrame.Create(bmp));
            //    encoder.Save(fs);//保存到路径中
            //    fs.Close();//释放资源
            //    fs.Dispose();
            //}
        }
        static void DoEvents()
        {
            DispatcherFrame frame = new DispatcherFrame(true);
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate (object arg)
            {
                DispatcherFrame fr = arg as DispatcherFrame;
                fr.Continue = false;
            }, frame);
            Dispatcher.PushFrame(frame);
        }

        List<int> listAllWords = new List<int>();

        /// <summary>   
        /// 随机产生常用汉字   
        /// </summary>   
        /// <param name="count">要产生汉字的个数</param>   
        /// <returns>常用汉字</returns>   
        private string GenerateChineseWords(int count)
        {
            string chineseWords = "";
            Encoding gb = Encoding.GetEncoding("gb2312");
            for (int i = 0; i < count; i++)
            {
                if (random.Next(100) > 95) 
                {
                    chineseWords += AllPunctuation.ElementAt(random.Next(AllPunctuation.Length));
                }

                if (listAllWords.Count == 0)
                {
                    int totolcount = 40 * 93 - 5;
                    for (int j = 0; j < totolcount; j++)
                    {
                        listAllWords.Add(j);
                    }
                }
                int code = listAllWords[random.Next(listAllWords.Count)];
                // 获取区码(常用汉字的区码范围为16-55)   
                //int regionCode = random.Next(16, 56);
                int regionCode = 16 + code / 93;
                // 获取位码(位码范围为1-94 由于55区的90,91,92,93,94为空,故将其排除)   
                int positionCode = 1 + code % 93;
                //if (regionCode == 55)
                //{
                //    // 55区排除90,91,92,93,94   
                //    positionCode = random.Next(1, 90);
                //}
                //else
                //{
                //    positionCode = random.Next(1, 95);
                //}

                // 转换区位码为机内码   
                int regionCode_Machine = regionCode + 160;// 160即为十六进制的20H+80H=A0H   
                int positionCode_Machine = positionCode + 160;// 160即为十六进制的20H+80H=A0H   

                // 转换为汉字   
                byte[] bytes = new byte[] { (byte)regionCode_Machine, (byte)positionCode_Machine };
                chineseWords += gb.GetString(bytes);
            }

            return chineseWords;
        }

        private void btnExportWords_Click(object sender, RoutedEventArgs e)
        {
            ExportAllTxt();
        }

        private void btnShowFonts_Click(object sender, RoutedEventArgs e)
        {
            string test_label = "0123ABCDabcd你我他，。：-,.:";
            TextBlock tbText = new TextBlock();
            tbText.FontSize = 24;
            tbText.Width = 512;
            tbText.Background = Brushes.White;
            cvText.Children.Add(tbText);
            if (!Directory.Exists("Fonts"))
            {
                Directory.CreateDirectory("Fonts");
            }
            foreach (FontFamily font in Fonts.SystemFontFamilies)
            {
                tbText.Text = test_label;
                tbText.FontFamily = font;
                DoEvents();
                FileStream fs = new FileStream(@"Fonts/" + font.Source + ".jpg", FileMode.Create);//保存在特定路径
                RenderTargetBitmap bmp = new RenderTargetBitmap((int)tbText.ActualWidth, (int)tbText.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                bmp.Render(tbText);
                BitmapEncoder encoder = new JpegBitmapEncoder();//对象的集合编码转成图像流
                encoder.Frames.Add(BitmapFrame.Create(bmp));
                encoder.Save(fs);//保存到路径中
                fs.Close();//释放资源
                fs.Dispose();
            }
            cvText.Children.Clear();
        }
    }
}
